package com.github.cyf.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.read.listener.PageReadListener;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.github.cyf.common.constants.ExcelConstants;
import com.github.cyf.common.excel.ExcelUtil;
import com.github.cyf.common.excel.entity.ExcelPageResult;
import com.github.cyf.common.util.ExecutorUtil;
import com.github.cyf.entity.ActResultLog;
import com.github.cyf.service.ActResultLogService;
import com.github.cyf.service.ExcelService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.function.Consumer;

/**
 * @author chenyifan
 * @create 2024-04-06 11:34
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class ExcelServiceImpl implements ExcelService {

    private final ActResultLogService actResultLogService;
    private final Executor threadPoolTaskExecutor;

    @Override
    public void exportDataToExcel(OutputStream os) {
        // 导出 100w 条数据，实际情况可以根据筛选条件获取到需要导出的数据量
        int totalCount = 100_0000;

        // 计算 excel 导出配置
        ExcelPageResult pageResult = ExcelUtil.calculateExportConfiguration(totalCount, ExcelConstants.SHEET_ROW_COUNT, ExcelConstants.WRITE_ROW_COUNT);
        int sheetNum = pageResult.getSheetNum();
        int oneSheetWriterCount = pageResult.getOneSheetWriterCount();
        int lastSheetWriteCount = pageResult.getLastSheetWriteCount();

        long startTime = System.currentTimeMillis();
        int currentPage = 0, realCount = 0;
        try(ExcelWriter excelWriter = EasyExcel.write(os, ActResultLog.class).build()) {
            // 外层循环是 Sheet 数目
            for (int i = 0; i < sheetNum; i++) {
                WriteSheet sheet = EasyExcel.writerSheet().sheetNo(i).sheetName("sheet" + i).build();
                // 内层循环是写入次数
                for (int j = 0; j < (i == sheetNum - 1 ? lastSheetWriteCount : oneSheetWriterCount); j++) {
                    // 分批次查询和分批次写入
                    List<ActResultLog> dataList = actResultLogService.pageQuery(currentPage, ExcelConstants.WRITE_ROW_COUNT);
                    if (CollectionUtils.isEmpty(dataList)) {
                        continue;
                    }
                    excelWriter.write(dataList, sheet);
                    currentPage++;
                    realCount += dataList.size();
                    log.info("第 {} 页数据导出完成", currentPage);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        long endTime = System.currentTimeMillis();
        log.info("导出 {} 条数据，用时:{}ms", realCount, (endTime - startTime));
    }

    public void batchImportDataByJdbc(String filePath) {
        batchImportData(filePath, actResultLogService::insertDataByJDBC);
    }

    @Override
    public void batchImportDataByMybatis(String filePath) {
        batchImportData(filePath, actResultLogService::insertDataByMybatis);
    }

    private void batchImportData(String filePath, Consumer<List<ActResultLog>> consumer) {
        long startReadTime = System.currentTimeMillis();

        // 获取所有 sheet
        List<ReadSheet> sheetList = ExcelUtil.getAllSheet(filePath);
        List<Runnable> tasks = new ArrayList<>();

        for (int i = 0; i < sheetList.size(); i++) {
            final int index = i;
            tasks.add(() -> {
                PageReadListener<ActResultLog> pageReadListener = new PageReadListener(consumer);
                EasyExcel.read(filePath, pageReadListener).sheet(sheetList.get(index).getSheetName()).head(ActResultLog.class).doRead();
            });
        }
        ExecutorUtil.syncExecute(threadPoolTaskExecutor, tasks);
        long endReadTime = System.currentTimeMillis();

        log.info("导入总花费时长：{}s", ((endReadTime - startReadTime) / 1000));
    }
}
